#pragma once

#include <sys/epoll.h>
#include <iostream>
#include <unistd.h>
#include <string>
#include <unordered_map>
namespace ns_reactor
{
    static int epoll_size = 128;
    class Event;
    class Reactor;
    typedef void (*callback_t)(Event &);

    class Event
    {
    public:
        int sock_;   // 特定一个文件描述符
        Reactor *r_; // 指向该Event对应的epoll

        std::string inbuffer_;  // 对应的sock，私有的读取缓冲区
        std::string outbuffer_; // 对应的sock，私有的输出缓冲区

        callback_t recv_callback_;  // 对应的sock，读回调
        callback_t send_callback_;  // 对应的sock，写回调
        callback_t error_callback_; // 对应的sock，错误回调
    public:
        Event() : sock_(-1), r_(nullptr)
        {
            recv_callback_ = nullptr;
            send_callback_ = nullptr;
            error_callback_ = nullptr;
        }
        void RegisterCallback(callback_t _recv, callback_t _send, callback_t _error)
        {
            recv_callback_ = _recv;
            send_callback_ = _send;
            error_callback_ = _error;
        }
        ~Event()
        {
        }
    };

    class Reactor
    {
        int epfd_;
        std::unordered_map<int, Event> map_events_;

    public:
        Reactor() : epfd_(-1)
        {
        }
        ~Reactor()
        {
            if (epfd_ > 0)
                close(epfd_);
        }
        void InitReactort()
        {
            epfd_ = epoll_create(epoll_size);
            if (epfd_ < 0)
            {
                std::cerr << "epoll_create errno!" << std::endl;
                exit(-1);
            }
        }
        void AddEvent(const Event &ev, uint32_t events)
        {
            // 将ev中的sock添加到epoll中
            // 将ev本省添加到unordered_map中

            struct epoll_event epoll_ev;
            epoll_ev.events = events;
            epoll_ev.data.fd = ev.sock_;

            if (epoll_ctl(epfd_, EPOLL_CTL_ADD, ev.sock_, &epoll_ev) < 0)
            {
                std::cerr << "epoll_ctl error!" << ev.sock_ << std::endl;
                return;
            }
            else
            {
                map_events_.insert({ev.sock_, ev});
            }
            std::cout << "添加事情成功，sock：" << ev.sock_ << std::endl;
        }
        void DelEvent(int sock)
        {
            auto iter = map_events_.find(sock);
            if (iter == map_events_.end())
            {
                // 没有找到
                return;
            }
            // 存在，将删除
            epoll_ctl(epfd_, EPOLL_CTL_DEL, sock, nullptr);
            map_events_.erase(iter);
            close(sock);

            std::cout << "client quit or error,删除相关资源" << std::endl;
        }
        // 使能更改读写接口
        void EnableReadWrite(int sock, bool readable, bool writeable)
        {
            struct epoll_event ev;
            ev.data.fd = sock;
            ev.events = (EPOLLET | (readable ? EPOLLIN : 0) | (writeable ? EPOLLOUT : 0));
            if (epoll_ctl(epfd_, EPOLL_CTL_MOD, sock, &ev) == 0)
            {
                std::cout << "更改 " << sock << " 读写事件成功" << std::endl;
            }
        }
        bool IsExists(int sock)
        {
            auto iter = map_events_.find(sock);
            return iter == map_events_.end() ? false : true;
        }
        // 对就绪事件进行事件派发
        void Dispatcher(int timeout)
        {
#define NUM 128
            struct epoll_event revs[NUM];
            int num = epoll_wait(epfd_, revs, NUM, timeout);
            for (int i = 0; i < num; i++)
            {
                // 就绪事件派发
                int sock = revs[i].data.fd;
                uint32_t event = revs[i].events;
                std::cout << "sock: " << sock << " 这个fd上面有数据" << std::endl;

                // 将所有的异常，全部交给读写处理
                // 读写处理遇到的所有的异常，都交给error_callback处理
                // 所有的异常事件，都会归类error_callback处理
                if (event & EPOLLERR)
                    event |= (EPOLLIN | EPOLLOUT);
                if (event & EPOLLHUP)
                    event |= (EPOLLIN | EPOLLOUT); // 对端关闭链接

                if (IsExists(sock) && (event & EPOLLIN))
                    if (map_events_[sock].recv_callback_)
                        map_events_[sock].recv_callback_(map_events_[sock]);
                if (IsExists(sock) && (event & EPOLLOUT))
                    if (map_events_[sock].send_callback_)
                        map_events_[sock].send_callback_(map_events_[sock]);
            }
        }
    };
}
